<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Coder-nav-记账本</title>
    <script src="/js/jquery/jquery.js"></script>
    <script src="/js/jquery/adsorb.js"></script>
    <script src="/js/vue/vue.js"></script>
    <script src="/js/vue/axios.js"></script>
    <script src="/js/vue/element-ui.js"></script>
    <script src="/js/echarts/echarts.js"></script>
    <script src="/js/echarts/westeros.js"></script>
    <script src="/js/util.js"></script>
    <style>
        @import url("/css/vue/element-ui.css");
        #main {
            position: absolute;
            width: 65%;
            height: 1px;
            top: 50px;
            left: 50%;
            transform: translate(-50%, 0);
        }
        .el-table__body-wrapper::-webkit-scrollbar {
            display: none;
        }
        .calculator {
            position: absolute;
            width: 300px;
            background-color: #fff;
            border-radius: 10px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            overflow: hidden;
            user-select: none;
            z-index: 1000;
        }
        .calculator-header {
            padding: 10px;
            background-color: #007bff;
            color: white;
            cursor: move;
            text-align: center;
            position: relative;
        }
        .calculator-header .close-btn {
            position: absolute;
            right: 10px;
            top: 50%;
            transform: translateY(-50%);
            background: none;
            border: none;
            color: white;
            font-size: 18px;
            cursor: pointer;
        }
        .calculator-header .close-btn:hover {
            color: #ff4d4d;
        }
        .calculator-body {
            padding: 20px;
        }
        .calculator-display {
            width: 100%;
            height: 50px;
            font-size: 24px;
            text-align: right;
            padding: 10px;
            box-sizing: border-box;
            border: 1px solid #ccc;
            border-radius: 5px;
            margin-bottom: 10px;
            user-select: auto;
            -webkit-user-select: auto;
        }
        .calculator-buttons {
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            gap: 10px;
        }
        .calculator-buttons button {
            padding: 20px;
            font-size: 18px;
            border: none;
            border-radius: 5px;
            background-color: #f1f1f1;
            cursor: pointer;
            transition: background-color 0.2s;
        }
        .calculator-buttons button:hover {
            background-color: #ddd;
        }
        .calculator-buttons button.operator {
            background-color: #007bff;
            color: white;
        }
        .calculator-buttons button.operator:hover {
            background-color: #0056b3;
        }
        .calculator-buttons button.equal {
            background-color: #28a745;
            color: white;
            grid-column: span 2;
        }
        .calculator-buttons button.equal:hover {
            background-color: #218838;
        }
        .calculator-display:focus {
            outline: 2px solid #007bff;
            outline-offset: -2px;
        }
        .calculator-buttons button {
            pointer-events: auto;
        }
    </style>
</head>
<body>
<div id="app">
    <el-page-header @back="goBack" style="position: fixed;z-index: 999;">
        <template #content>
            <el-select ref="selectRef" v-model="selectedState" size="small" style="width: 155px">
                <el-option label="🍡&emsp;导航主页" value="0"><el-link href="/">🍡&emsp;导航主页</el-link></el-option>
                <el-option label="📌&emsp;记事本" value="1"><el-link href="/memo">📌&emsp;记事本</el-link></el-option>
                <el-option label="💰&emsp;记账本" value="2"><el-link href="/cash">💰&emsp;记账本</el-link></el-option>
                <el-option label="🌈&emsp;动态页面" value="3"><el-link href="/page">🌈&emsp;动态页面</el-link></el-option>
                <el-option label="⏱️&emsp;定时任务" value="4"><el-link href="/task">⏱️&emsp;定时任务</el-link></el-option>
                <el-option label="⚙️&emsp;个人设置" value="5"><el-link href="/setting">⚙️&emsp;个人设置</el-link></el-option>
                <el-option label="📖&emsp;帮助手册" value="6"><el-link href="/readme">📖&emsp;帮助手册</el-link></el-option>
                <el-option label="🛠️&emsp;接口文档" value="7"><el-link href="/doc.html">🛠️&emsp;接口文档</el-link></el-option>
                <el-option label="↪️&emsp;退出登录" value="-1" @click.native="clearToken"></el-option>
            </el-select>
            <el-button size="small" @click="showCalculator">📅 计算器 </el-button>
            <el-tag effect="plain" type="success">收入: ￥{{addSum}}</el-tag>
            <el-tag effect="plain" type="danger">支出: ￥{{subSum}}</el-tag>
            <el-tag effect="plain" type="warning">日均: ￥{{avgSum}}</el-tag>
        </template>
    </el-page-header>
    <div id="main" align="center">
        <template>
            <!-- 表格数据 -->
            <el-table :data="[{}].concat(tableData).concat([{}])"
                      border style="width: 1264px">

                <!-- 消费日期 -->
                <el-table-column align="center" prop="createDate" label="消费日期" width="160" fixed="left">
                    <template slot-scope="scope">
                        <el-date-picker v-if="scope.$index===0" v-model="createDate" type="date" placeholder="消费日期" style="width: 135px"></el-date-picker>
                        <el-date-picker value-format="yyyy-MM-dd" v-if="scope.row.id > 0" v-model="scope.row.createDate" type="date" style="width: 135px" readonly></el-date-picker>
                        <el-date-picker value-format="yyyy-MM-dd" v-if="scope.$index===tableData.length+1"
                                        v-model="searchCreateDate"
                                        type="daterange"
                                        range-separator="~"
                                        start-placeholder="始"
                                        end-placeholder="  终"
                                        style="width: 135px"></el-date-picker>
                    </template>
                </el-table-column>

                <!-- 消费类型 -->
                <el-table-column align="center" prop="typeDesc" label="消费类型" width="130">
                    <template slot-scope="scope">
                        <el-select v-if="scope.$index===0" v-model="type" size="large" style="width: 100px">
                            <el-option v-for="item in typeList" :key="item.value" :label="item.value" :value="item.key"/>
                        </el-select>
                        <span v-if="scope.row.id > 0">{{scope.row.typeDesc}}</span>
                        <el-select v-if="scope.$index===tableData.length+1" v-model="searchType" multiple clearable size="large" style="width: 75px">
                            <el-option v-for="item in typeList" :key="item.value" :label="item.value" :value="item.key"/>
                        </el-select>
                    </template>
                </el-table-column>

                <!-- 消费渠道 -->
                <el-table-column align="center" prop="channel" label="消费渠道" width="140">
                    <template slot-scope="scope">
                        <el-select v-if="scope.$index===0" v-model="channel" size="large" style="width: 110px">
                            <el-option v-for="item in channelList" :key="item.value" :label="item.value" :value="item.key"/>
                        </el-select>
                        <el-select v-if="scope.$index===tableData.length+1" v-model="searchChannel" multiple clearable size="large" style="width: 75px">
                            <el-option v-for="item in channelList" :key="item.value" :label="item.value" :value="item.key"/>
                        </el-select>
                        <el-tag v-if="scope.row.channel===0" type="info">银联</el-tag>
                        <el-tag v-if="scope.row.channel===1" type="success">微信</el-tag>
                        <el-tag v-if="scope.row.channel===2" type="primary">支付宝</el-tag>
                    </template>
                </el-table-column>

                <!-- 标题 -->
<!--                <el-table-column prop="title" label="标题" width="184">-->
<!--                    <template slot-scope="scope">-->
<!--                        <el-input v-if="scope.$index===0" class="add" v-model="title" placeholder="标题" style="width: 160px"></el-input>-->
<!--                        <span v-if="scope.row.id > 0" style="padding-left: 15px">{{scope.row.title}}</span>-->
<!--                        <el-input v-if="scope.$index===tableData.length+1" class="add" v-model="searchTitle" placeholder="标题" style="width: 160px"></el-input>-->
<!--                    </template>-->
<!--                </el-table-column>-->

                <!-- 备注 -->
                <el-table-column prop="remark" label="备注" width="300">
                    <template slot-scope="scope">
                        <el-input v-if="scope.$index===0" class="add" v-model="remark" placeholder="备注" type="textarea" :rows="1" style="width: 275px"></el-input>
                        <span v-if="scope.row.id > 0 && scope.row.remark !== ''" style="padding-left: 15px">{{scope.row.remark}}</span>
                        <span v-if="scope.row.id > 0 && scope.row.remark === ''" style="padding-left: 15px">--</span>
                        <el-input v-if="scope.$index===tableData.length+1" class="add" v-model="searchRemark" placeholder="备注" type="textarea" :rows="1" style="width: 275px"></el-input>
                    </template>
                </el-table-column>

                <!-- 收支 -->
                <el-table-column align="center" prop="flag" label="收支" clearable width="130">
                    <template slot-scope="scope">
                        <el-select v-if="scope.$index===0" v-model="flag" style="width: 100px">
                            <el-option v-for="item in flagList" :key="item.value" :label="item.value" :value="item.key"/>
                        </el-select>
                        <el-tag v-if="scope.row.flag===0" type="danger">支出</el-tag>
                        <el-tag v-if="scope.row.flag===1" type="success">收入</el-tag>
                        <el-select v-if="scope.$index===tableData.length+1" v-model="searchFlag" multiple style="width: 75px">
                            <el-option v-for="item in flagList" :key="item.value" :label="item.value" :value="item.key"/>
                        </el-select>
                    </template>
                </el-table-column>

                <!-- 消费金额 -->
                <el-table-column prop="money" label="消费金额" width="120">
                    <template slot-scope="scope">
                        <el-input v-if="scope.$index===0" class="add" v-model="money" placeholder="金额" style="width: 95px"></el-input>
                        <el-tag v-if="scope.row.id > 0" effect="plain" type="warning">￥{{scope.row.money}}</el-tag>
                        <el-tag v-if="scope.$index===tableData.length+1" effect="plain" type="warning">💴{{cash}}</el-tag>
                    </template>
                </el-table-column>

                <!-- 操作 -->
                <el-table-column align="center" prop="id" label="操作" fixed="right" min-width="155">
                    <template slot-scope="scope">
                        <!-- 新增 -->
                        <el-button v-if="scope.$index===0"
                                   plain
                                   size="mini"
                                   type="info"
                                   @click="clearAddParams">重置</el-button>
                        <el-button v-if="scope.$index===0"
                                   size="mini"
                                   type="success"
                                   @click="save">新增</el-button>
                        <!-- 表格 -->
                        <el-button v-if="scope.row.id > 0"
                                   plain
                                   size="mini"
                                   type="info"
                                   @click="del(scope.row.id)">删除</el-button>
                        <el-button v-if="scope.row.id > 0"
                                   plain
                                   size="mini"
                                   type="primary"
                                   @click="getInfo(scope.row.id)">详情</el-button>
                        <!-- 查询 -->
                        <el-button v-if="scope.$index===tableData.length+1"
                                   plain
                                   size="mini"
                                   type="info"
                                   @click="clearSearchParams">重置</el-button>
                        <el-button v-if="scope.$index===tableData.length+1"
                                   size="mini"
                                   type="primary"
                                   @click="initData">查询</el-button>
                    </template>
                </el-table-column>

            </el-table>

            <!-- 表单 -->
            <el-drawer :visible.sync="infoDrawer" title="详情" :append-to-body="true">
                <template>
                    <el-form label-width="auto" style="padding-left: 35px; padding-right: 30px">
                        <el-form-item label="消费日期">
                            <el-date-picker value-format="yyyy-MM-dd" v-model="infoCreateDate" type="date" placeholder="消费日期"></el-date-picker>
                        </el-form-item>
                        <el-form-item label="消费渠道">
                            <el-select v-model="infoChannel" size="large">
                                <el-option v-for="item in channelList" :key="item.value" :label="item.value" :value="item.key"/>
                            </el-select>
                        </el-form-item>
                        <el-form-item label="消费类型">
                            <el-select v-model="infoType" size="large">
                                <el-option v-for="item in typeList" :key="item.value" :label="item.value" :value="item.key"/>
                            </el-select>
                        </el-form-item>
<!--                        <el-form-item label="标题">-->
<!--                            <el-input class="add" v-model="infoTitle" placeholder="标题"></el-input>-->
<!--                        </el-form-item>-->
                        <el-form-item label="收支">
                            <el-select v-model="infoFlag">
                                <el-option v-for="item in flagList" :key="item.value" :label="item.value" :value="item.key"/>
                            </el-select>
                        </el-form-item>
                        <el-form-item label="消费金额">
                            <el-input class="add" v-model="infoMoney" placeholder="消费金额"></el-input>
                        </el-form-item>
                        <el-form-item label="备注">
                            <el-input class="add" v-model="infoRemark" placeholder="备注" type="textarea" :rows="4"></el-input>
                        </el-form-item>
                        <el-form-item>
                            <el-button size="mini" type="primary" @click="edit">保存</el-button>
                            <el-button size="mini" type="info" plain @click="getInfo(infoId)">重置</el-button>
                        </el-form-item>
                    </el-form>
                </template>
            </el-drawer>

            <!-- 分页 -->
            <el-pagination align='right' layout="total, sizes, prev, pager, next"
                           @size-change="changeSize"
                           @current-change="changeCur"
                           :current-page="pageIndex" :page-size="pageSize" :total="totalCount">
            </el-pagination>

            <br/><br/><br/>

            <!-- 线性图 -->
            <div id="month_line" style="width: 49%; height:400px; display: inline-block"></div>
            <!-- 饼状图 -->
            <div id="title_pie" style="width: 49%; height: 400px; display: inline-block"></div>
            <br/><br/><br/>
            <!-- 饼状图-收支 -->
<!--            <div id="sum_pie" style="width: 49%; height: 400px; display: inline-block"></div>-->
            <!-- 柱状图 -->
<!--            <div id="type_bar" style="width: 49%; height:400px; display: inline-block"></div>-->

        </template>
        <br/><br/>
    </div>
    <div class="calculator" :style="{ top: top + 'px', left: left + 'px' }" v-show="isVisible" @click="handleCalculatorClick">
        <div class="calculator-header" @mousedown="startDrag">
            Coder-nav
            <button class="close-btn" @click="closeCalculator">×</button>
        </div>
        <div class="calculator-body">
            <input type="text" class="calculator-display" v-model="display"
                   ref="calcInput"
                   @keydown="handleKeyDown"
                   @paste="handlePaste">
            <div class="calculator-buttons">
                <button @click="clear">C</button>
                <button @click="appendOperator('/')" class="operator">/</button>
                <button @click="appendOperator('*')" class="operator">*</button>
                <button @click="backspace">←</button>
                <button @click="appendNumber(7)">7</button>
                <button @click="appendNumber(8)">8</button>
                <button @click="appendNumber(9)">9</button>
                <button @click="appendOperator('-')" class="operator">-</button>
                <button @click="appendNumber(4)">4</button>
                <button @click="appendNumber(5)">5</button>
                <button @click="appendNumber(6)">6</button>
                <button @click="appendOperator('+')" class="operator">+</button>
                <button @click="appendNumber(1)">1</button>
                <button @click="appendNumber(2)">2</button>
                <button @click="appendNumber(3)">3</button>
                <button @click="appendDecimal()">.</button>
                <button @click="appendNumber(0)" style="grid-column: span 2;">0</button>
                <button class="equal" @click="calculate">=</button>
            </div>
        </div>
    </div>
</div>
<script th:inline="javascript">
    window.addEventListener("popstate", function(e) {
        console.log("###")
    }, false);
    // 表格
    var curDate = new Date();
    var Main = {
        data() {
            return {
                selectedState: '2',
                infoDrawer: false,
                cash: 0,
                addSum: 0,
                subSum: 0,
                avgSum: 0,
                // 登录
                token: '',
                // 新增
                createDate: curDate,
                title: '',
                flag: 0,
                money: '',
                channel: 1,
                type: 1,
                remark: '',
                // 查询
                searchCreateDate: null,
                searchTitle: null,
                searchFlag: null,
                searchMoney: null,
                searchChannel: null,
                searchType: null,
                searchRemark: null,
                // 详情
                infoId: null,
                infoCreateDate: null,
                infoTitle: null,
                infoFlag: null,
                infoMoney: null,
                infoChannel: null,
                infoType: null,
                infoRemark: null,
                // 表格
                pageIndex: 1,
                pageSize: 10,
                totalCount: 0,
                tableData: [],
                channelList: [],
                flagList: [],
                typeList: [],
                // 计算器相关数据
                display: '',
                top: 60,
                left: 15,
                dragging: false,
                dragStartX: 0,
                dragStartY: 0,
                isVisible: false,
                lastInputWasOperator: false,
            }
        },
        mounted:function() {
            // 检查Token
            this.checkToken()
        },
        methods: {
            initData() {
                this.getCash()
                this.getSum()
                this.getAvg()
                this.getPage()
                this.getChartLine('month', '')
                this.getChartPie('title', '')
                // this.getChartPieSum('', '')
                // this.getChartBar('type', '')
            },
            checkToken() {
                localStorage.setItem('jump', window.location.href);
                axios.get('/login/checkToken', {
                    params: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    if(!response.data.data) {
                        localStorage.setItem('token', '')
                        window.location.href = '/login'
                        return;
                    }
                    this.getChannelList()
                    this.getFlagList()
                    this.getTypeList()
                    this.initData()
                });
            },
            // 返回
            goBack() {
                history.back()
            },
            // 余额
            getCash() {
                axios.get('/cash/getCash', {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    this.$data.cash = response.data.data;
                });
            },
            // 收支
            getSum() {
                // 收入
                var params1 = this.getParams(null);
                params1.flags = [1]
                axios.post('/cash/getSum', params1, {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    this.$data.addSum = response.data.data;
                });
                // 支出
                var params0 = this.getParams(null);
                params0.flags = [0]
                axios.post('/cash/getSum', params0, {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    this.$data.subSum = response.data.data;
                });
            },
            // 日均
            getAvg() {
                var params = this.getParams(null);
                axios.post('/cash/getAvg', params, {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    this.$data.avgSum = response.data.data;
                });
            },
            // 查询参数
            getParams(groupBy) {
              return {
                  pageIndex: this.$data.pageIndex,
                  pageSize: this.$data.pageSize,
                  startDate: this.$data.searchCreateDate == null ? null : this.$data.searchCreateDate[0],
                  endDate: this.$data.searchCreateDate == null ? null : this.$data.searchCreateDate[1],
                  title: this.$data.searchTitle,
                  remark: this.$data.searchRemark,
                  flags: this.$data.searchFlag,
                  channels: this.$data.searchChannel,
                  types: this.$data.searchType,
                  groupBy: groupBy,
              };
            },
            // 重置新增参数
            clearAddParams() {
                this.$data.title = null
                this.$data.money = null
                this.$data.remark = null
            },
            // 重置查询参数
            clearSearchParams() {
                this.$data.searchCreateDate = null
                this.$data.searchTitle = null
                this.$data.searchRemark = null
                this.$data.searchFlag = null
                this.$data.searchChannel = null
                this.$data.searchType = null
                this.initData()
            },
            // 分页
            getPage() {
                this.$loading()
                axios.post('/cash/getPage', this.getParams(null), {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    this.$data.pageIndex = response.data.data.pageIndex;
                    this.$data.pageSize = response.data.data.pageSize;
                    this.$data.totalCount = response.data.data.totalCount;
                    this.$data.tableData = response.data.data.data;
                    this.$loading().close()
                }).catch((response) => {
                    this.$loading().close()
                    this.$message.error(response)
                });
            },
            // 支付渠道
            getChannelList() {
                axios.get('/cash/getChannelList', {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    this.$data.channelList = response.data.data;
                }).catch((response) => {
                    this.$message.error(response)
                });
            },
            // 收支
            getFlagList() {
                axios.get('/cash/getFlagList', {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    this.$data.flagList = response.data.data;
                });
            },
            // 支付类型
            getTypeList() {
                axios.get('/cash/getTypeList', {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    this.$data.typeList = response.data.data;
                });
            },
            // 新增
            save() {
                this.$loading()
                var createDate = this.$data.createDate;
                axios.post('/cash/save', {
                    year: createDate.getFullYear(),
                    month: createDate.getMonth() + 1,
                    day: createDate.getDate(),
                    title: this.$data.title,
                    flag: this.$data.flag,
                    money: this.$data.money,
                    channel: this.$data.channel,
                    type: this.$data.type,
                    remark: this.$data.remark,
                }, {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    if(response.data.code === 200) {
                        this.clearAddParams()
                        this.initData()
                        this.$message.info('新增成功')
                    } else {
                        this.$message.error(response.data.msg)
                    }
                }).catch((response) => {
                    this.$loading().close()
                    this.$message.error(response)
                });
            },
            // 编辑
            edit() {
                var infoCreateDate = new Date(this.$data.infoCreateDate);
                axios.post('/cash/save', {
                    id: this.$data.infoId,
                    year: infoCreateDate.getFullYear(),
                    month: infoCreateDate.getMonth() + 1,
                    day: infoCreateDate.getDate(),
                    title: this.$data.infoTitle,
                    flag: this.$data.infoFlag,
                    money: this.$data.infoMoney,
                    channel: this.$data.infoChannel,
                    type: this.$data.infoType,
                    remark: this.$data.infoRemark,
                }, {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    if(response.data.code === 200) {
                        this.initData()
                        this.$message.info('保存成功')
                    } else {
                        this.$message.error(response.data.msg)
                    }
                }).catch((response) => {
                    this.$message.error(response)
                });
            },
            // 删除
            del(id) {
                this.$confirm('确认删除？', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    axios.delete('/cash/delete', {
                        params: {
                            id: id
                        },
                        headers: {
                            token: localStorage.getItem('token')
                        }
                    }).then((response) => {
                        this.initData()
                        this.$message.info('删除成功')
                    });
                }).catch((response) => {
                    this.$message.error(response)
                });
            },
            // 分页
            changeSize(number) {
                this.$data.pageSize = number
                this.initData()
            },
            // 分页
            changeCur(number) {
                this.$data.pageIndex = number
                this.initData()
            },
            // 详情
            getInfo(id) {
                this.$data.infoDrawer = true
                axios.get('/cash/getInfo', {
                    params: {
                        id: id
                    },
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    this.$data.infoId = response.data.data.id
                    this.$data.infoCreateDate = response.data.data.createDate
                    this.$data.infoTitle = response.data.data.title
                    this.$data.infoFlag = response.data.data.flag
                    this.$data.infoMoney = response.data.data.money
                    this.$data.infoChannel = response.data.data.channel
                    this.$data.infoType = response.data.data.type
                    this.$data.infoRemark = response.data.data.remark
                }).catch((response) => {
                    this.$message.error(response)
                });
            },
            // 分组
            getGroupBy(groupBy) {
                if(groupBy === 'create_date') {
                    return '消费日期'
                }
                if(groupBy === 'channel') {
                    return '消费渠道'
                }
                if(groupBy === 'type') {
                    return '消费类型'
                }
                if(groupBy === 'flag') {
                    return '收支'
                }
                if(groupBy === 'title') {
                    return '标题'
                }
                return '';
            },
            // 柱状图
            getChartBar(groupBy, title) {
                axios.post('/cash/getChartBar', this.getParams(groupBy), {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    var bar = echarts.init(document.getElementById(groupBy + '_bar'), 'westeros');
                    var option = {
                        title: {
                            text: title,
                        },
                        legend: {
                            left: 'left',
                        },
                        dataset: {
                            dimensions: response.data.data.dimensions,
                            source: response.data.data.data,
                        },
                        xAxis: { type: 'category' },
                        yAxis: {},
                        series: [{ type: 'bar' }, { type: 'bar' }]
                    };
                    bar.setOption(option);
                });
            },
            // 线型图
            getChartLine(groupBy, title) {
                axios.post('/cash/getChartLine', this.getParams(groupBy), {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    var line = echarts.init(document.getElementById(groupBy + '_line'), 'westeros');
                    var option = {
                        title: {
                            text: title,
                        },
                        tooltip: {
                            trigger: 'axis',
                        },
                        legend: {
                            left: 'left',
                            data: response.data.data.legend,
                        },
                        grid: {
                            left: '3%',
                            right: '4%',
                            bottom: '3%',
                            containLabel: true,
                        },
                        xAxis: {
                            type: 'category',
                            boundaryGap: false,
                            data: response.data.data.xaxis,
                        },
                        yAxis: {
                            type: 'log',
                        },
                        series: response.data.data.data,
                    };
                    line.setOption(option);
                });
            },
            // 饼状图
            getChartPie(groupBy, title) {
                axios.post('/cash/getChartPie', this.getParams(groupBy), {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    var pie = echarts.init(document.getElementById(groupBy + '_pie'), 'light');
                    var option = {
                        title: {
                            text: title,
                            left: 'center',
                        },
                        tooltip: {
                            trigger: 'item',
                        },
                        legend: {
                            orient: 'vertical',
                            left: 'left',
                        },
                        series: [
                            {
                                name: '',
                                type: 'pie',
                                radius: '50%',
                                data: response.data.data.data,
                                emphasis: {
                                    itemStyle: {
                                        shadowBlur: 10,
                                        shadowOffsetX: 0,
                                        shadowColor: 'rgba(0, 0, 0, 0.5)'
                                    }
                                }
                            }
                        ]
                    };
                    pie.setOption(option);
                });
            },
            // 饼状图-收支
            getChartPieSum(groupBy, title) {
                axios.post('/cash/getChartPieSum', this.getParams(groupBy), {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    var pie = echarts.init(document.getElementById('sum_pie'), 'light');
                    var option = {
                        title: {
                            text: title,
                            left: 'center',
                        },
                        tooltip: {
                            trigger: 'item',
                        },
                        legend: {
                            orient: 'vertical',
                            left: 'left',
                        },
                        series: [
                            {
                                name: '',
                                type: 'pie',
                                radius: '50%',
                                data: response.data.data.data,
                                emphasis: {
                                    itemStyle: {
                                        shadowBlur: 10,
                                        shadowOffsetX: 0,
                                        shadowColor: 'rgba(0, 0, 0, 0.5)'
                                    }
                                }
                            }
                        ]
                    };
                    pie.setOption(option);
                });
            },
            // 雷达图
            getChartRadar(groupBy, title) {
                axios.post('/cash/getChartRadar', this.getParams(groupBy), {
                    headers: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    var radar = echarts.init(document.getElementById(groupBy + '_radar'), 'westeros');
                    var option = {
                        title: {
                            text: title,
                        },
                        legend: {
                            left: 'left',
                            data: response.data.data.legend,
                        },
                        radar: {
                            radius: '65%',
                            indicator: response.data.data.indicator,
                        },
                        series: [
                            {
                                type: 'radar',
                                data: response.data.data.data,
                            }
                        ]
                    };
                    radar.setOption(option);
                });
            },
            // 计算器方法
            appendNumber(number) {
                if (this.display === '0' || this.display === 'Error') {
                    this.display = number.toString();
                } else {
                    this.display += number.toString();
                }
                this.lastInputWasOperator = false;
            },

            appendDecimal() {
                if (this.display === '' || this.display === 'Error') {
                    this.display = '0.';
                } else if (!this.display.includes('.')) {
                    this.display += '.';
                }
                this.lastInputWasOperator = false;
            },

            appendOperator(operator) {
                if (this.display === 'Error') {
                    return;
                }

                if (this.display !== '' && !this.lastInputWasOperator) {
                    // 确保表达式以数字结尾
                    if (!isNaN(this.display[this.display.length - 1])) {
                        this.display += operator;
                        this.lastInputWasOperator = true;
                    }
                } else if (this.display === '' && operator === '-') {
                    // 允许负号开头
                    this.display = '-';
                    this.lastInputWasOperator = false;
                }
            },

            clear() {
                this.display = '';
                this.lastInputWasOperator = false;
            },

            backspace() {
                if (this.display === 'Error') {
                    this.display = '';
                    return;
                }

                if (this.display.length > 0) {
                    this.display = this.display.slice(0, -1);
                    if (this.display.length === 0) {
                        this.lastInputWasOperator = false;
                    } else {
                        const lastChar = this.display[this.display.length - 1];
                        this.lastInputWasOperator = isNaN(lastChar) && lastChar !== '.';
                    }
                }
            },

            calculate() {
                if (this.display === '' || this.display === 'Error') {
                    return;
                }

                try {
                    // 处理表达式末尾的操作符
                    let expression = this.display;
                    if (isNaN(expression[expression.length - 1])) {
                        expression = expression.slice(0, -1);
                    }

                    if (expression === '') {
                        this.display = '0';
                        return;
                    }

                    // 使用更精确的计算方法
                    const result = this.safeEval(expression);
                    this.display = this.formatNumber(result);
                } catch (e) {
                    this.display = 'Error';
                }
                this.lastInputWasOperator = false;
            },

            safeEval(expression) {
                // 使用Function构造器来避免直接使用eval
                try {
                    // 处理精度问题
                    const tokens = expression.split(/([+\-*/])/);
                    let numbers = [];
                    let operators = [];

                    // 提取数字和操作符
                    tokens.forEach(token => {
                        if (token.match(/^[+\-*/]$/)) {
                            operators.push(token);
                        } else if (token !== '') {
                            numbers.push(parseFloat(token));
                        }
                    });

                    // 先处理乘除法
                    let i = 0;
                    while (i < operators.length) {
                        const op = operators[i];
                        if (op === '*' || op === '/') {
                            const a = numbers[i];
                            const b = numbers[i + 1];
                            let result;

                            if (op === '*') {
                                result = this.multiply(a, b);
                            } else {
                                if (b === 0) {
                                    throw new Error('Division by zero');
                                }
                                result = this.divide(a, b);
                            }

                            // 替换计算过的值和操作符
                            numbers.splice(i, 2, result);
                            operators.splice(i, 1);
                        } else {
                            i++;
                        }
                    }

                    // 再处理加减法
                    let total = numbers[0];
                    for (let j = 0; j < operators.length; j++) {
                        const op = operators[j];
                        const num = numbers[j + 1];

                        if (op === '+') {
                            total = this.add(total, num);
                        } else {
                            total = this.subtract(total, num);
                        }
                    }

                    return total;
                } catch (e) {
                    throw e;
                }
            },

            // 精确加法
            add(a, b) {
                const aDecimals = (a.toString().split('.')[1] || '').length;
                const bDecimals = (b.toString().split('.')[1] || '').length;
                const maxDecimals = Math.max(aDecimals, bDecimals);
                const factor = Math.pow(10, maxDecimals);
                return (this.multiply(a, factor) + this.multiply(b, factor)) / factor;
            },

            // 精确减法
            subtract(a, b) {
                return this.add(a, -b);
            },

            // 精确乘法
            multiply(a, b) {
                const aStr = a.toString();
                const bStr = b.toString();
                const aDecimals = (aStr.split('.')[1] || '').length;
                const bDecimals = (bStr.split('.')[1] || '').length;
                const factor = Math.pow(10, aDecimals + bDecimals);

                const aInt = parseInt(aStr.replace('.', ''), 10);
                const bInt = parseInt(bStr.replace('.', ''), 10);

                return (aInt * bInt) / factor;
            },

            // 精确除法
            divide(a, b) {
                const aStr = a.toString();
                const bStr = b.toString();
                const aDecimals = (aStr.split('.')[1] || '').length;
                const bDecimals = (bStr.split('.')[1] || '').length;
                const factor = Math.pow(10, aDecimals - bDecimals);

                const aInt = parseInt(aStr.replace('.', ''), 10);
                const bInt = parseInt(bStr.replace('.', ''), 10);

                return (aInt / bInt) * factor;
            },

            // 格式化数字，去除不必要的尾随零
            formatNumber(num) {
                // 如果是整数，直接返回
                if (Number.isInteger(num)) {
                    return num.toString();
                }

                // 处理浮点数
                let str = num.toString();
                if (str.indexOf('.') !== -1) {
                    // 去除尾随的零
                    str = str.replace(/0+$/, '');
                    // 如果小数点后没有数字，去除小数点
                    if (str.endsWith('.')) {
                        str = str.slice(0, -1);
                    }
                }
                return str;
            },

            // 处理键盘输入
            handleKeyDown(event) {
                const key = event.key;

                // 数字键
                if (/^[0-9]$/.test(key)) {
                    this.appendNumber(parseInt(key, 10));
                    event.preventDefault();
                    return;
                }

                // 操作符
                if (/^[+\-*/]$/.test(key)) {
                    this.appendOperator(key);
                    event.preventDefault();
                    return;
                }

                // 小数点
                if (key === '.') {
                    this.appendDecimal();
                    event.preventDefault();
                    return;
                }

                // 计算
                if (key === 'Enter' || key === '=') {
                    this.calculate();
                    event.preventDefault();
                    return;
                }

                // 退格
                if (key === 'Backspace') {
                    this.backspace();
                    event.preventDefault();
                    return;
                }

                // 清除
                if (key === 'Escape') {
                    this.clear();
                    event.preventDefault();
                    return;
                }

                // 允许这些键的默认行为
                if ([
                    'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown',
                    'Tab', 'Home', 'End'
                ].includes(key)) {
                    return;
                }

                // 阻止其他按键
                event.preventDefault();
            },

            // 聚焦输入框并处理点击事件
            focusInput(event) {
                // 如果点击的是关闭按钮，不聚焦
                if (event.target.classList.contains('close-btn')) {
                    return;
                }

                // 聚焦输入框
                this.$refs.calcInput.focus();

                // 如果点击的是计算器面板（不是按钮或输入框），可以添加额外逻辑
                if (event.target === this.$el) {
                    // 例如：点击空白处清空输入
                    // this.clear();
                }
            },

            // 处理计算器点击
            handleCalculatorClick(event) {
                // 如果点击的是关闭按钮，不处理
                if (event.target.classList.contains('close-btn')) {
                    return;
                }

                // 聚焦输入框
                this.$refs.calcInput.focus();
            },

            // 清理粘贴数据
            sanitizePasteData(data) {
                return data
                    .replace(/\s+/g, '')       // 移除所有空白
                    .replace(/，/g, '.')       // 中文逗号转小数点
                    .replace(/×/g, '*')        // 中文乘号
                    .replace(/÷/g, '/')        // 中文除号
                    .replace(/[^\d+\-*/.]/g, ''); // 移除非数学字符
            },

            // 处理粘贴的数据
            processPastedData(data) {
                // 如果当前显示错误或0，替换内容
                if (this.display === 'Error' || this.display === '0') {
                    this.display = data;
                }
                // 否则追加内容
                else {
                    this.display += data;
                }
            },

            // 修改后的粘贴处理
            handlePaste(event) {
                // 允许粘贴操作
                event.preventDefault();

                // 获取粘贴内容
                const pasteData = (event.clipboardData || window.clipboardData)
                    .getData('text/plain')
                    .trim();

                if (!pasteData) return;

                // 清理粘贴内容
                const sanitized = this.sanitizePasteData(pasteData);
                if (!sanitized) return;

                // 处理粘贴内容
                this.processPastedData(sanitized);
            },

            // 新增方法：清理粘贴内容
            sanitizeInput(input) {
                return input
                    .replace(/\s+/g, '')
                    .replace(/，/g, '.')
                    .replace(/×/g, '*')
                    .replace(/÷/g, '/')
                    .replace(/−/g, '-')
                    .replace(/＋/g, '+')
                    .replace(/[^-+*/.0-9]/g, ''); // 移除非数学字符
            },

            startDrag(event) {
                this.dragging = true;
                this.dragStartX = event.clientX - this.left;
                this.dragStartY = event.clientY - this.top;
                document.addEventListener('mousemove', this.onDrag);
                document.addEventListener('mouseup', this.stopDrag);
            },

            onDrag(event) {
                if (this.dragging) {
                    this.left = event.clientX - this.dragStartX;
                    this.top = event.clientY - this.dragStartY;
                }
            },

            stopDrag() {
                this.dragging = false;
                document.removeEventListener('mousemove', this.onDrag);
                document.removeEventListener('mouseup', this.stopDrag);
            },

            closeCalculator() {
                this.isVisible = false;
            },

            showCalculator() {
                this.isVisible = true;
                this.$nextTick(() => {
                    this.$refs.calcInput.focus();
                });
            },
            clearToken() {
                axios.get('/logout', {
                    params: {
                        token: localStorage.getItem('token')
                    }
                }).then((response) => {
                    localStorage.setItem('token', '')
                    this.checkToken()
                    this.$message.info("退出登录成功")
                })
            },
            jump(url) {
                window.location.href = url
            },
        }
    };
    var Ctor = Vue.extend(Main);
    new Ctor().$mount('#app');
</script>
</body>
</html>